﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Bovril.PlayingCards.French;

namespace Bovril.Poker
{
    public enum HoleCategory
    {
        Pair,
        SuitedNonPair,
        OffsuitNonPair
    }

    public class HoleArchetype : IEquatable<HoleArchetype>, IComparable<HoleArchetype>
    {
        public HoleArchetype(Hole hole)
        {
            Card1Rank = hole.Card1.Rank;
            Card2Rank = hole.Card2.Rank;

            if (Card1Rank == Card2Rank)
            {
                Category = HoleCategory.Pair;
            }
            else if (hole.Card1.Suit == hole.Card2.Suit)
            {
                Category = HoleCategory.SuitedNonPair;
            }
            else
            {
                Category = HoleCategory.OffsuitNonPair;
            }
        }

        private HoleArchetype(BinaryReader binaryReader)
        {
            int dataVersion = binaryReader.ReadInt32();
            if (dataVersion != currentDataVersion_)
                throw new FormatException("Invalid HoleArchetype data version");
            String categoryText = binaryReader.ReadString();
            Category = (HoleCategory)Enum.Parse(typeof(HoleCategory), categoryText);
            Card1Rank = binaryReader.ReadInt32();
            Card2Rank = binaryReader.ReadInt32();
            WinPercentile = binaryReader.ReadDouble();
            OrderIndex = binaryReader.ReadInt32();
        }

        internal static HoleArchetype Load(BinaryReader binaryReader)
        {
            return new HoleArchetype(binaryReader);
        }

        internal void Save(BinaryWriter binaryWriter)
        {
            binaryWriter.Write(currentDataVersion_);
            binaryWriter.Write(Category.ToString());
            binaryWriter.Write(Card1Rank);
            binaryWriter.Write(Card2Rank);
            binaryWriter.Write(WinPercentile);
            binaryWriter.Write(OrderIndex);
        }

        public override int GetHashCode()
        {
            return (int)Category + (Card1Rank << 2) + (Card2Rank << 8);
        }

        public override string ToString()
        {
            return String.Format("{0}, {1} ({2})", RankValue.ToString(Card1Rank), RankValue.ToString(Card2Rank), Category.ToString());
        }

        public bool Equals(HoleArchetype other)
        {
            return (this.Category == other.Category && this.Card1Rank == other.Card1Rank && this.Card2Rank == other.Card2Rank);
        }

        public int CompareTo(HoleArchetype other)
        {
            if (this.Category < other.Category)
                return -1;
            else if (this.Category > other.Category)
                return 1;

            if (this.Card1Rank < other.Card1Rank)
                return -1;
            else if (this.Card1Rank > other.Card1Rank)
                return 1;

            if (this.Card2Rank < other.Card2Rank)
                return -1;
            else if (this.Card2Rank > other.Card2Rank)
                return 1;

            return 0;
        }

        private const int currentDataVersion_ = 1;

        public HoleCategory Category { get; private set; }
        public int Card1Rank { get; private set; }
        public int Card2Rank { get; private set; }

        public double WinPercentile { get; internal set; }
        public int OrderIndex { get; internal set; }
    }
}
